#ifndef SRC_OLED_C_
#define SRC_OLED_C_
#include <mcs51/8052.h>
#include "oled.h"
#include "oledfont.h" //取模的中文库
#define _nop_() __asm NOP __endasm
#define SCL P2_5
#define SDA P2_3

// 在指定位置显示一个字符,包括部分字符
// x:0~127
// y:0~7 页
void OLED_ShowChar(uchar x, uchar y, uchar chr)
{
    OLED_Write_Cmd(0xB0 + y); // page0--page7
    // 每个page从0列
    OLED_Write_Cmd(((x & 0xf0) >> 4) | 0x10);
    OLED_Write_Cmd((x & 0x0f) | 0x01);
    uchar c = chr - ' ';
    for (int i = 0; i < 6; i++)
        OLED_Write_Data(F6x8[c][i]);
}

// 显示一个16进制的字符
void OLED_ShowHex(uchar x, uchar y, uchar chr)
{
    uchar str[5] = {'0', 'x', '0', '0','\0'};
    str[2] = HexChar[chr >> 4];
    str[3] = HexChar[chr & 0x0F];
    OLED_ShowString(x, y, str);
}

// 显示一个字符号串

void OLED_ShowString(uchar x, uchar y, uchar *chr)
{
    uchar j = 0;
    while (chr[j] != '\0')
    {
        OLED_ShowChar(x, y, chr[j++]);
        x += 6;
        if (x > 120)
        {
            x = 0;
            y++;
        }
    }
}

void OLED_ShowNum(uchar x, uchar y, signed long num)
{
    uchar showChar;
    uchar str[20] = {0};
    uchar index = 0;
    uchar isNegative = 0;
    if (num < 0)
    {
        isNegative = 1;
        num = num * -1;
    }
    while (num >= 0)
    {
        if (num < 10)
        {
            str[index++] = num;
            break;
        }
        else
        {
            str[index++] = num % 10;
            num = num / 10;
        }
    }

    if (isNegative == 1)
    {
        OLED_ShowChar(x, y, '-');
        x += 6;
    }
    while (--index > 0)
    {
        OLED_ShowChar(x, y, str[index] + '0');
        x += 6;
        if (x > 120)
        {
            x = 0;
            y++;
        }
    }
    OLED_ShowChar(x, y, str[0] + '0');
}

void OLED_ShowCharl(uchar x, uchar y, uchar chr)
{
    OLED_Write_Cmd(0xB0 + y); // page0--page7
    // 每个page从0列
    OLED_Write_Cmd(((x & 0xf0) >> 4) | 0x10);
    OLED_Write_Cmd((x & 0x0f) | 0x01);
    uchar c = chr - ' ';
    for (int i = 0; i < 8; i++)
        OLED_Write_Data(F8X16[c][i]);

    OLED_Write_Cmd(0xB0 + y + 1); // page0--page7
    // 每个page从0列
    OLED_Write_Cmd(((x & 0xf0) >> 4) | 0x10);
    OLED_Write_Cmd((x & 0x0f) | 0x01);
    for (int i = 0; i < 8; i++)
        OLED_Write_Data(F8X16[c][8 + i]);
}
void OLED_ShowStringl(uchar x, uchar y, uchar *chr)
{
    uchar j = 0;
    while (chr[j] != '\0')
    {
        OLED_ShowCharl(x, y, chr[j++]);
        x += 8;
        if (x > 120)
        {
            x = 0;
            y = y + 2;
        }
    }
}
/**
 * 	-2147483648~+2147483648
 */
void OLED_ShowNuml(uchar x, uchar y, signed long num)
{
    uchar showChar;
    uchar str[20] = {0};
    uchar index = 0;
    uchar isNegative = 0;
    if (num < 0)
    {
        isNegative = 1;
        num = num * -1;
    }
    while (num >= 0)
    {
        if (num < 10)
        {
            str[index++] = num;
            break;
        }
        else
        {
            str[index++] = num % 10;
            num = num / 10;
        }
    }

    if (isNegative == 1)
    {
        OLED_ShowCharl(x, y, '-');
        x += 8;
    }
    while (--index > 0)
    {
        OLED_ShowCharl(x, y, str[index] + '0');
        x += 8;
        if (x > 120)
        {
            x = 0;
            y = y + 2;
        }
    }
    OLED_ShowCharl(x, y, str[0] + '0');
}

void IIC_Start()
{
    SCL = 0;
    SDA = 1;
    SCL = 1; // SCL一直为高电平
    _nop_(); // SDA为高电平，持续时间>4.7us
    SDA = 0; // SDA跳变成低电平，表示起始信号
    _nop_(); // 低电平持续时间>4us
}

void IIC_Stop()
{
    SCL = 0;
    SDA = 0;
    SCL = 1;
    _nop_(); // SDA为低电平，持续时间>4us
    SDA = 1; // 跳变到高电平，终止信号
    _nop_(); // 高电平持续时间>4.7us
}

char IIC_ACK() // 判断是否有效应答
{
    char flag;
    SDA = 1; // 在脉冲9释放数据线
    _nop_(); // 等待一段时间
    SCL = 1; // 在SCL高电平期间去读取SDA的状态
    _nop_();
    flag = SDA; // 在SCL为高电平期间，读取SDA信号
    _nop_();
    SCL = 0;
    _nop_();

    return flag; // 返回读取的SDA状态
}

void IIC_Send_Byte(char dataSend) // 发送一个字节时序
{
    char i;
    for (i = 0; i < 8; i++)
    {                          // 每循环一次发送1位数据
        SCL = 0;               // 拉低SCL，让SDA做好发数据准备
        SDA = dataSend & 0x80; // 建立发送数据，&操作取出发送的最高位
        _nop_();               // 发送数据建立时间
        SCL = 1;               // SCL为高电平，开始发送数据
        _nop_();               // 发送数据时间
        SCL = 0;               // 发送完毕
        _nop_();
        dataSend <<= 1; // 左移将第二个数据放到最高位，以便下一次发送
    }
}

void OLED_Write_Cmd(char dataCmd)
{
    // 1.Start 开始信号
    IIC_Start();
    // 2. Slave Address从机地址(011110(SA0)(R/W#)  SA0控制接入多个显示屏的选择 R/W#设置0为写入模式)
    IIC_Send_Byte(0x78); // 0111 1000   0x78
    // 3. 是否有效应答
    IIC_ACK();
    // 4. Control byte  ((C0)(D/C)000000)   C0设置0表示传输的内容为Data byte   D/0为0写入指令  为1写入数据
    IIC_Send_Byte(0x00); // 0000 0000   0x00
    // 5. ACK
    IIC_ACK();
    // 6. 写入指令/数据
    IIC_Send_Byte(dataCmd); // 写入数据
    // 7. ACK
    IIC_ACK();
    // 8.STOP
    IIC_Stop();
}

void OLED_Write_Data(char dataData)
{
    // 1.Start（IIC_Start） 开始信号
    IIC_Start();
    // 2. Slave Address从机地址(011110(SA0)(R/W#)  SA0控制接入多个显示屏的选择 R/W#设置0为写入模式)
    IIC_Send_Byte(0x78); // 0111 1000   0x78
    // 3. 是否有效应答
    IIC_ACK();
    // 4. Control byte  ((C0)(D/C)000000)   C0设置0表示传输的内容为Data byte   D/0为0写入指令  为1写入数据
    IIC_Send_Byte(0x40); // 0100 0000   0x40
    // 5. ACK
    IIC_ACK();
    // 6. 写入指令/数据
    IIC_Send_Byte(dataData); // 写入数据
    // 7. ACK
    IIC_ACK();
    // 8.STOP
    IIC_Stop();
}

void OLED_Init()
{
    OLED_Write_Cmd(0xAE); //--display off
    OLED_Write_Cmd(0x00); //---set low column address
    OLED_Write_Cmd(0x10); //---set high column address
    OLED_Write_Cmd(0x40); //--set start line address
    OLED_Write_Cmd(0xB0); //--set page address
    OLED_Write_Cmd(0x81); // contract control
    OLED_Write_Cmd(0xFF); //--128
    OLED_Write_Cmd(0xA1); // set segment remap
    OLED_Write_Cmd(0xA6); //--normal / reverse
    OLED_Write_Cmd(0xA8); //--set multiplex ratio(1 to 64)
    OLED_Write_Cmd(0x3F); //--1/32 duty
    OLED_Write_Cmd(0xC8); // Com scan direction
    OLED_Write_Cmd(0xD3); //-set display offset
    OLED_Write_Cmd(0x00); //

    OLED_Write_Cmd(0xD5); // set osc division
    OLED_Write_Cmd(0x80); //

    OLED_Write_Cmd(0xD8); // set area color mode off
    OLED_Write_Cmd(0x05); //

    OLED_Write_Cmd(0xD9); // Set Pre-Charge Period
    OLED_Write_Cmd(0xF1); //

    OLED_Write_Cmd(0xDA); // set com pin configuartion
    OLED_Write_Cmd(0x12); //

    OLED_Write_Cmd(0xDB); // set Vcomh
    OLED_Write_Cmd(0x30); //

    OLED_Write_Cmd(0x8D); // set charge pump enable
    OLED_Write_Cmd(0x14); //

    OLED_Write_Cmd(0xAF); //--turn on oled panel
}

void OLED_Clear() // 给屏幕写入0
{
    unsigned char i, j;
    for (i = 0; i < 8; i++)
    { // Page0~Page
        //	选择Page
        OLED_Write_Cmd(0xB0 + i);
        //	每选择一次Page，重新让光标指向0列
        OLED_Write_Cmd(0x00);
        OLED_Write_Cmd(0x10);
        for (j = 0; j < 128; j++)
        {                       // 显示屏大小128x64
            OLED_Write_Data(0); // 0列到127列依次写入0，每写入数据，列地址自动偏移
        }
    }
}

#endif // SRC_OLED_C_
